/**
 * Copyright 2008 Mathias Doenitz, http://lis.to/
 *
 * This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
 * redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
 * If not, see http://www.gnu.org/licenses/
 */

package listo.client.dialogs.controllers;

import com.google.inject.Inject;
import listo.client.ContextManager;
import listo.client.Formatter;
import listo.client.Lang;
import listo.client.model.Context;
import listo.client.model.Folder;
import listo.client.model.ObjectId;
import listo.client.model.Task;
import listo.utils.MiscUtils;
import listo.utils.StringUtils2;
import listo.utils.guice.ManuallyScoped;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.StringEscapeUtils;

import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.text.DateFormat;
import java.util.Set;

@ManuallyScoped("TaskDialogScope")
public class TaskClearTextController implements ComponentController<Task>, ComponentController.ModelChangedListener {

    private final Formatter formatter;
    private final DateFormat dateFormat;
    private final DateFormat timeFormat;
    private final Context currentContext;

    private JEditorPane clearText;
    private Task task;
    private String wrapperTag;

    @Inject
    public TaskClearTextController(Formatter formatter, Lang lang, ContextManager contextManager,
                                   TaskQuickEntryController quickEntryController,
                                   TaskFoldersController foldersController,
                                   TaskReminderController reminderController,
                                   TaskDescController descController,
                                   TaskDueDateController dueDateController,
                                   TaskDueTimeController dueTimeController) {
        this.formatter = formatter;
        dateFormat = lang.getDateFormat();
        timeFormat = lang.getTimeFormat();
        currentContext = contextManager.getCurrentContext();

        quickEntryController.addModelChangedListener(this);
        foldersController.addModelChangedListener(this);
        reminderController.addModelChangedListener(this);
        descController.addModelChangedListener(this);
        dueDateController.addModelChangedListener(this);
        dueTimeController.addModelChangedListener(this);

        Font font = UIManager.getFont("Label.font");
        wrapperTag = String.format("<span style=\"font-family:%s;font-size:%spt;font-weight:bold\">",
                font.getName(), font.getSize());
    }

    public JEditorPane getComponent() {
        return clearText;
    }

    public void setDialogComponent(JDialog dialog, JComponent component) {
        clearText = (JEditorPane) component;
        clearText.addHyperlinkListener(new HyperlinkListener() {
            public void hyperlinkUpdate(HyperlinkEvent e) {
                if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
                    MiscUtils.openBrowser(e.getURL().toString());
                }
            }
        });
    }

    public void setModelObject(Task modelObject) {
        task = modelObject;
        modelChanged();
    }

    public void addModelChangedListener(ModelChangedListener listener) {
    }

    public void modelChanged(ComponentController... controllers) {
        // if this is a secondary model change event we don't need to update
        if (controllers.length > 1) return;

        StringBuilder sb = new StringBuilder(wrapperTag);

        String desc = task.getDesc();
        if (StringUtils.isNotEmpty(desc)) {
            MiscUtils.UrlMatch[] urls = MiscUtils.findUrls(desc);
            if (urls.length > 0) {
                int offset = 0;
                for (MiscUtils.UrlMatch urlMatch : urls) {
                    int preLen = desc.length();
                    desc = StringUtils2.replace(desc, urlMatch.startIndex + offset, urlMatch.endIndex + offset,
                            String.format("<a href=\"%1$s\">%1$s</a>", urlMatch.url));
                    int postLen = desc.length();
                    offset += postLen - preLen;
                }
            }
            sb.append(StringEscapeUtils.escapeHtml(desc));
        }

        if (task.hasDueDate()) sb.append(" on ").append(task.getDue().format(dateFormat));
        if (task.hasDueTime()) sb.append(" at ").append(task.getDue().format(timeFormat));
        if (task.hasReminder()) {
            sb.append(", remind me ");
            sb.append(formatter.toLongReminderString(task.getDue(), task.getReminder()));
        }

        sb.append('.');

        Set<ObjectId> folderIds = task.getFolders();
        if (folderIds != null) {
            sb.append("<br/>Folders: ");
            ObjectId[] folderIdList = folderIds.toArray(new ObjectId[folderIds.size()]);
            for (int i = 0; i < folderIdList.length; i++) {
                Folder folder = currentContext.getFolder(folderIdList[i]);
                if (i > 0) sb.append(i < folderIdList.length - 1 ? ", " : " and ");
                sb.append('@').append(folder.getPathName());
            }
        }

        sb.append("</span>");

        clearText.setText(sb.toString());
    }

    public void focusGained(FocusEvent e) {
    }

    public void focusLost(FocusEvent e) {
    }

    public boolean isComponentValid() {
        return true;
    }

}
